Skip to content

Respect Coder depth#904

Merged
byroot merged 2 commits into
ruby:masterfrom
etiennebarrie:respect-coder-depth
Nov 27, 2025
Merged

Respect Coder depth#904
byroot merged 2 commits into
ruby:masterfrom
etiennebarrie:respect-coder-depth

Conversation

@etiennebarrie

Copy link
Copy Markdown
Contributor

Builds on #903.

While working on #903, I realized JSON::Coder wasn't respecting the depth it's given:

$ ruby -rjson -e 'puts JSON::Coder.new(object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 1).dump(foo: 42)' \
> -e 'puts JSON::State.new(object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 1).generate(foo: 42)'
{
  "foo": 42
}
{
    "foo": 42
  }

This is not ideal, for example a user could want to emit pretty generated JSON, using Russian-doll caching and JSON::Fragment (or a custom solution). To me it's a bug, so I just fixed it, now that generate_json_data has its own depth it's pretty straightforward: etiennebarrie/json@move-depth-to-generate_json_data...etiennebarrie:json:respect-coder-depth

@etiennebarrie etiennebarrie changed the title Respect coder depth Respect Coder depth Nov 25, 2025
@byroot

byroot commented Nov 26, 2025

Copy link
Copy Markdown
Member

This needs rebasing now.

That said, it never occurred to me that depth could be used as a configuration for pretty printing purposes. But if it works, why not.

@byroot

byroot commented Nov 26, 2025

Copy link
Copy Markdown
Member

Testing old versions, seems like this never really worked?

gem "json", "2.2.0"
require 'json'

puts "JSON::VERSION: #{JSON::VERSION}"
puts JSON.generate({ foo: 1 }, object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 4)
$ ruby /tmp/test.rb
JSON::VERSION: 2.2.0
{
          "foo": 1
        }

Coder currently ignores its depth and always resets it to 0 when
generating a new JSON document.
@etiennebarrie

Copy link
Copy Markdown
Contributor Author

Testing old versions, seems like this never really worked?

I'm not sure what you mean, your example shows that JSON.generate always respected depth?

@byroot

byroot commented Nov 27, 2025

Copy link
Copy Markdown
Member

your example shows that JSON.generate always respected depth?

Look at the opening braces. It's not respecting the depth. But the rest yes.

@etiennebarrie

Copy link
Copy Markdown
Contributor Author

The opening brace being on the first character is expected, because the enclosing code should be already indenting that part. For example, to go from a fragment with depth 1 to an Array:

puts "[\n  #{JSON.generate({ foo: 1 }, object_nl: "\n", array_nl: "\n", space: " ", indent: "  ", depth: 1)}\n]"
[
  {
    "foo": 1
  }
]

@byroot

byroot commented Nov 27, 2025

Copy link
Copy Markdown
Member

Ah right, that makes sense.

@byroot byroot merged commit 9c36681 into ruby:master Nov 27, 2025
37 checks passed
@etiennebarrie

etiennebarrie commented Nov 27, 2025

Copy link
Copy Markdown
Contributor Author

Another example, using the generator to do the Array part instead of String interpolation:

gem "json", ARGV.first
require 'json'

puts "JSON::VERSION: #{JSON::VERSION}"

cache_miss = 0
cache = Hash.new do |h, k|
  cache_miss += 1
  h[k] = Fragment.new(JSON.pretty_generate({ foo: k }, depth: 1))
end

class Fragment
  def initialize(fragment)
    @fragment = fragment
  end

  def to_json(*)
    @fragment
  end
end

puts JSON.pretty_generate((1..3).map(&cache))
puts "miss:#{cache_miss}"
cache_miss = 0
puts JSON.pretty_generate((1..3).map(&cache))
puts "miss:#{cache_miss}"

This works all the way to ruby 2.7 for example:

$ cat test.rb | container run --rm -i ruby:2.7 ruby
JSON::VERSION: 2.3.0             
[
  {
    "foo": 1
  },
  {
    "foo": 2
  },
  {
    "foo": 3
  }
]
miss:3
[
  {
    "foo": 1
  },
  {
    "foo": 2
  },
  {
    "foo": 3
  }
]
miss:0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants